﻿#region Using directives

using System;
using System.Reflection;
using System.Reflection.Emit;
using System.Collections.Generic;
using System.Text;

#endregion

namespace Ndo
{
    public static class Degenerate<T>
        where T : class
    {
        static Degenerate()
        { }
        static Dictionary<Predicate<MemberInfo>, ConstructorInfo> dict = new Dictionary<Predicate<MemberInfo>, ConstructorInfo>();
        public static T From(T target, Predicate<MemberInfo> degeneratePredicate)
        {
            if (target == null)
                return null;
            if(degeneratePredicate == null)
                throw new ArgumentNullException();
            ConstructorInfo ci;
            lock (dict)
            {
                if (!dict.TryGetValue(degeneratePredicate, out ci))
                {
                    dict[degeneratePredicate] = ci = new DegenerateFactory<T>(
                        string.Format("Degenerate[{0}]{1}", typeof(T).FullName, BoxHelper.GetId()), 
                        degeneratePredicate).CI;
                }
            }
            return (T)ci.Invoke(new object[] { target });
        }



        #region With
        public static class With<A>
            where A : Attribute
        {
            private static readonly ConstructorInfo CI;
            public static T From(T target)
            {
                if (target == null)
                    return null;
                return (T)CI.Invoke(new object[] { target });
            }
            static With()
            {
                CI = new DegenerateFactory<T>(
                    string.Format("Degenerate[{0}]With[{1}]{2}", typeof(T).FullName, typeof(A).FullName,BoxHelper.GetId()),
                    predicate).CI;
            }

            static bool predicate(MemberInfo mi)
            {
                return mi.GetCustomAttributes(typeof(A), false).Length > 0;
            }
        }
        #endregion

        #region WithOut
        public static class WithOut<A>
            where A : Attribute
        {
            private static readonly ConstructorInfo CI;
            public static T From(T target)
            {
                if (target == null)
                    return null;
                return (T)CI.Invoke(new object[] { target });
            }
            static WithOut()
            {
                CI = new DegenerateFactory<T>(
                    string.Format("Degenerate[{0}]]WithOut[{1}]{2}", typeof(T).FullName, typeof(A).FullName, BoxHelper.GetId()),
                    predicate).CI;
            }
            static bool predicate(MemberInfo mi)
            {
                return mi.GetCustomAttributes(typeof(A), false).Length == 0;
            }
        }
        #endregion
    }
}